package graphics.fingerprint;

import java.io.IOException;
import java.io.InputStream;

import toolkit.SystemInfo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.DisplayMetrics;
import android.view.View;

public class PaintView extends View {

	private Bitmap bitmap;
	private Canvas canvas;
	private Matrix imageMatrix = new Matrix();
	private Matrix markMatrix = new Matrix();
	private Path path;
	private Paint paint;
	private float mX, mY;

	public static final int SOURCEPREPARED_PIC = 100;
	private static final float TOUCH_TOLERANCE = 4;

	private UserController controller;
	private SourceHandler sourceHandler;

	public PaintView(Context c) {
		super(c);

		setBitmap(this.getCanvasBitmap());
		// new Alerter(getContext()).alert(SystemInfo.getDisplayMetrics(
		// this.getContext()).toString());
		// mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);

		canvas = new Canvas(getBitmap());
		path = new Path();
		paint = new Paint();

		Looper looper = Looper.myLooper();
		sourceHandler = new SourceHandler(looper);

		this.setFocusable(true);
		this.setClickable(true);
		this.setLongClickable(true);
		this.setDrawingCacheEnabled(true);
		this.setPaintProperties();
	}

	private Bitmap getCanvasBitmap() {
		InputStream is = getResources().openRawResource(R.drawable.white);
		Bitmap bmp = BitmapFactory.decodeStream(is);
		try {
			is.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		DisplayMetrics dm = SystemInfo.getDisplayMetrics(this.getContext());
		bmp = Bitmap.createScaledBitmap(bmp,
				(int) (bmp.getWidth() / dm.scaledDensity), (int) (bmp
						.getHeight() / dm.scaledDensity), true);
		return bmp;
	}

	@Override
	protected void onDraw(Canvas c) {
		canvas.setBitmap(getBitmap());
		c.drawColor(0xFF0000AA);
		c.drawBitmap(getBitmap(), getImageMatrix(), paint);
		c.drawPath(path, paint);
	}

	protected void touch_start(float x, float y) {
		path.reset();
		path.moveTo(x, y);
		mX = x;
		mY = y;
	}

	protected void touch_move(float x, float y) {
		float dx = Math.abs(x - mX);
		float dy = Math.abs(y - mY);
		if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
			path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
			mX = x;
			mY = y;
		}
	}

	protected void touch_up() {
		path.lineTo(mX, mY);
		this.getImageMatrix().invert(this.markMatrix);
		path.transform(markMatrix);
		canvas.drawPath(path, paint);
		path.reset();
	}

	private void setPaintProperties() {
		paint.setAntiAlias(true);
		paint.setDither(true);
		paint.setColor(0xFFFF0000);
		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeJoin(Paint.Join.ROUND);
		paint.setStrokeCap(Paint.Cap.ROUND);
		paint.setStrokeWidth(3);
	}

	class SourceHandler extends Handler {
		public SourceHandler(Looper looper) {
			super(looper);
		}

		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case SOURCEPREPARED_PIC:
				PaintView.this.setBitmap((Bitmap) msg.obj);
				PaintView.this.post(new RefreshRunnable());
				// is this really valid???
				// maybe postInvalidate();
				break;
			}
			super.handleMessage(msg);
		}
	}

	class RefreshRunnable implements Runnable {
		@Override
		public void run() {
			PaintView.this.postInvalidate();
		}
	}

	public Handler getSourceHandler() {
		return this.sourceHandler;
	}

	public void setBitmap(Bitmap bitmap) {
		this.bitmap = bitmap;
	}

	private Bitmap getBitmap() {
		return bitmap;
	}

	public UserController getController() {
		return this.controller;
	}

	public void setController(UserController controller) {
		this.controller = controller;
	}

	public void setImageMatrix(Matrix matrix) {
		this.imageMatrix = matrix;
		this.getImageMatrix().invert(this.markMatrix);
	}

	public Matrix getImageMatrix() {
		return imageMatrix;
		
	}
}